home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Ham Radio 2000
/
Ham Radio 2000.iso
/
ham2000
/
tcp_ip
/
jnos
/
jnos_src
/
allocold.c
< prev
next >
Wrap
C/C++ Source or Header
|
1994-04-17
|
16KB
|
586 lines
/* memory allocation routines
* Copyright 1991 Phil Karn, KA9Q
*
* Adapted from alloc routine in K&R; memory statistics and interrupt
* protection added for use with net package. Must be used in place of
* standard Turbo-C library routines because the latter check for stack/heap
* collisions. This causes erroneous failures because process stacks are
* allocated off the heap.
*
* Mods by G1EMM , PA0GRI
*/
#include <dos.h>
#include <alloc.h>
#include "global.h"
#include "proc.h"
#include "cmdparse.h"
#include "mbuf.h"
#include "socket.h"
#include "daemon.h"
#ifdef EMS
#include "memlib.h"
#endif
#ifdef XMS
#include "xms.h"
#endif
static unsigned long Memfail; /* Count of allocation failures */
static unsigned long Allocs; /* Total allocations */
static unsigned long Frees; /* Total frees */
static unsigned long Invalid; /* Total calls to free with garbage arg */
static unsigned long Yellows; /* Yellow alert garbage collections */
static unsigned long Reds; /* Red alert garbage collections */
static unsigned long Overuse; /* Total calls to free with overused arg */
static unsigned long Intalloc; /* Calls to malloc with ints disabled */
static unsigned long Intfree; /* Calls to free with ints disabled */
static int Memwait; /* Number of tasks waiting for memory */
unsigned long Availmem; /* Heap memory, ABLKSIZE units */
static unsigned long Morecores;
#ifdef notdef
static int Efficient = 1; /* 0 = normal/fast, 1 = effecient/slow */
#endif
static int Memdebug = 0; /* 0 = normal, 1 = call logstat() */
#ifdef MULTITASK
unsigned Minheap = 16 * 1024; /* Min free heap when shelling out */
#endif
static char freewarn[] ="free: WARNING! %s (%Fp) pc = %04x:%04x proc %s%c";
static char freewarn1[] = "invalid pointer";
static char HeapSizeStr[] = "heap size %lu, avail %lu (%lu%%), morecores %lu, coreleft %lu";
static char AllocStr[] = "allocs %lu, frees %lu (diff %lu), alloc fails %lu\ninvalid frees %lu, overused %lu";
static char Threshold[] = "threshold %lu\n";
static char GarbageStr[] = "garbage collections yellow %lu, red %lu";
#ifdef notdef
static char EfficientStr[] = "efficient %u, threshold %lu";
#endif
static char EfficientStr[] = "threshold %lu";
static char InterruptStr[] = "interrupts-off calls to malloc %lu, free %lu\n";
#ifdef Kelvdebug
static char freewarn2[] = "overused buffer";
#endif
static unsigned long Sizes[16];
#ifdef EMS
extern int EMS_Available;
#endif
static int logstat __ARGS((void));
int dostat __ARGS((int argc,char *argv[],void *p));
static int dofreelist __ARGS((int argc,char *argv[],void *p));
static int doibufsize __ARGS((int argc,char *argv[],void *p));
static int donibufs __ARGS((int argc,char *argv[],void *p));
static int dothresh __ARGS((int argc,char *argv[],void *p));
static int dosizes __ARGS((int argc,char *argv[],void *p));
static int doefficient __ARGS((int argc,char *argv[],void *p));
static int domemdebug __ARGS((int argc,char *argv[],void *p));
static int dominheap __ARGS((int argc,char *argv[],void *p));
struct cmds Memcmds[] = {
"debug", domemdebug, 0, 0, NULLCHAR,
#ifdef notdef
"efficient",doefficient,0, 0, NULLCHAR,
#endif
"freelist", dofreelist, 0, 0, NULLCHAR,
"ibufsize", doibufsize, 0, 0, NULLCHAR,
#ifdef MULTITASK
"minheap", dominheap, 0, 0, NULLCHAR,
#endif
"nibufs", donibufs, 0, 0, NULLCHAR,
"sizes", dosizes, 0, 0, NULLCHAR,
"status", dostat, 0, 0, NULLCHAR,
"thresh", dothresh, 0, 0, NULLCHAR,
NULLCHAR,
};
#ifdef LARGEDATA
#define HUGE huge
#else
#define HUGE
#endif
union header {
struct {
union header HUGE *ptr;
unsigned long size;
} s;
#ifdef Kelvdebug
long l[2];
#endif
};
typedef union header HEADER;
#define NULLHDR (HEADER HUGE *)NULL
#define ABLKSIZE (sizeof (HEADER))
static HEADER HUGE *morecore __ARGS((unsigned nu));
static HEADER Base;
static HEADER HUGE *Allocp = NULLHDR;
static unsigned long Heapsize;
#ifdef Kelvdebug
#define MARKER 0x766c654bL /* Kelv in reverse */
#endif
/* Allocate block of 'nb' bytes */
void *
malloc(nb)
unsigned nb;
{
register HEADER HUGE *p, HUGE *q;
register unsigned nu;
int i;
if(!istate())
Intalloc++;
if(nb == 0)
return NULL;
/* Record the size of this request */
if((i = log2(nb)) >= 0)
Sizes[i]++;
#ifndef Kelvdebug
/* Round up to full block, then add one for header */
nu = ((nb + ABLKSIZE - 1) / ABLKSIZE) + 2; /* force allocated memory */
nu &= 0xfffffffeL; /* to be on offset 0x0008 */
#else
/* Round up to full block, then add one for header and one for debug */
nu = ((nb + ABLKSIZE - 1) / ABLKSIZE) + 4; /* force allocated memory */
nu &= 0xfffffffeL; /* to be on offset 0x0008 */
#endif
if ((q = Allocp) == NULLHDR){
Base.s.ptr = Allocp = q = &Base;
Base.s.size = 1;
}
#ifdef notdef
if(Efficient) {
Allocp = q = &Base; /* Start at the very beginning again */
}
#endif
for (p = q->s.ptr; ; q = p, p = p->s.ptr){
if (p->s.size >= nu){
/* This chunk is at least as large as we need */
if (p->s.size <= nu + 1){
/* This is either a perfect fit (size == nu)
* or the free chunk is just one unit larger.
* In either case, alloc the whole thing,
* because there's no point in keeping a free
* block only large enough to hold the header.
*/
q->s.ptr = p->s.ptr;
} else {
/* Carve out piece from end of entry */
p->s.size -= nu;
p += p->s.size;
p->s.size = nu;
}
p->s.ptr = p; /* for auditing */
#ifdef Kelvdebug
p->l[(p->s.size * 2) - 2] = (long)p; /* debug */
p->l[(p->s.size * 2) - 1] = MARKER; /* debug */
#endif
Allocs++;
Availmem -= p->s.size;
p++;
#ifdef LARGEDATA
/* On the brain-damaged Intel CPUs in
* "large data" model, make sure the offset field
* in the pointer we return isn't null.
* The Turbo C compiler and certain
* library functions like strrchr() assume this.
*/
if(FP_OFF(p) == 0){
/* Return denormalized but equivalent pointer */
return (void *)MK_FP(FP_SEG(p)-1,16);
}
#endif
return (void *)p;
}
if (p == Allocp && ((p = morecore(nu)) == NULLHDR)){
Memfail++;
return NULL;
}
}
}
/* Get more memory from the system and put it on the heap */
static HEADER HUGE *
morecore(nu)
unsigned nu;
{
register char HUGE *cp;
register HEADER HUGE *up;
Morecores++;
if ((int)(cp = (char HUGE *)sbrk(nu * ABLKSIZE)) == -1){
if(Memdebug) {
log(-1,"morecore: Failure requesting %lu (coreleft %lu)",
nu * ABLKSIZE,coreleft());
logstat();
}
return NULLHDR;
}
up = (HEADER *)cp;
up->s.size = nu;
up->s.ptr = up; /* satisfy audit */
#ifdef Kelvdebug
up->l[(up->s.size * 2) - 2] = (long)up; /* satisfy debug */
up->l[(up->s.size * 2) - 1] = MARKER; /* satisfy debug */
#endif
free((void *)(up + 1));
Heapsize += nu*ABLKSIZE;
Frees--; /* Nullify increment inside free() */
return Allocp;
}
/* Put memory block back on heap */
void
free(blk)
void *blk;
{
register HEADER HUGE *p, HUGE *q;
unsigned short HUGE *ptr;
if(!istate())
Intfree++;
if(blk == NULL)
return; /* Required by ANSI */
p = (HEADER HUGE *)blk - 1;
/* Audit check */
if(p->s.ptr != p){
ptr = (unsigned short *)&blk;
printf(freewarn,freewarn1,blk,ptr[-1],ptr[-2],Curproc->name,'\n');
fflush(stdout);
#ifdef STKTRACE
stktrace();
#endif
Invalid++;
log(-1,freewarn,freewarn1,blk,ptr[-1],ptr[-2],Curproc->name,' ');
logstat();
return;
}
#ifdef Kelvdebug
if(p->l[(p->s.size * 2) - 2] != (long)p || p->l[(p->s.size * 2) - 1] != MARKER){
ptr = (unsigned short *)&blk;
printf(freewarn,freewarn2,blk,ptr[-1],ptr[-2],Curproc->name,'\n');
fflush(stdout);
Overuse++;
log(-1,freewarn,freewarn2,blk,ptr[-1],ptr[-2],Curproc->name,' ');
logstat();
return;
}
#endif
Availmem += p->s.size;
/* Search the free list looking for the right place to insert */
for(q = Allocp; !(p > q && p < q->s.ptr); q = q->s.ptr){
/* Highest address on circular list? */
if(q >= q->s.ptr && (p > q || p < q->s.ptr))
break;
}
if(p + p->s.size == q->s.ptr){
/* Combine with front of this entry */
p->s.size += q->s.ptr->s.size;
p->s.ptr = q->s.ptr->s.ptr;
} else {
/* Link to front of this entry */
p->s.ptr = q->s.ptr;
}
if(q + q->s.size == p){
/* Combine with end of this entry */
q->s.size += p->s.size;
q->s.ptr = p->s.ptr;
} else {
/* Link to end of this entry */
q->s.ptr = p;
}
Frees++;
if(Memwait != 0)
psignal(&Memwait,0);
}
#ifdef notdef /* Not presently used */
/* Move existing block to new area */
void *
realloc(area,size)
void *area;
unsigned size;
{
unsigned osize;
HEADER HUGE *hp;
char HUGE *cp;
hp = ((HEADER *)area) - 1;
osize = (hp->s.size -1) * ABLKSIZE;
free(area); /* Hopefully you have your interrupts off , Phil. */
if((cp = malloc(size)) != NULL && cp != area)
memcpy((char *)cp,(char *)area,size>osize? osize : size);
return cp;
}
#endif
/* Allocate block of cleared memory */
void *
calloc(nelem,size)
unsigned nelem; /* Number of elements */
unsigned size; /* Size of each element */
{
register unsigned i;
register char *cp;
i = nelem * size;
if((cp = malloc(i)) != NULL)
memset(cp,0,i);
return cp;
}
/* Version of malloc() that waits if necessary for memory to become available */
void *
mallocw(nb)
unsigned nb;
{
register void *p;
while((p = malloc(nb)) == NULL){
Memwait++;
pwait(&Memwait);
Memwait--;
}
return p;
}
/* Version of calloc that waits if necessary for memory to become available */
void *
callocw(nelem,size)
unsigned nelem; /* Number of elements */
unsigned size; /* Size of each element */
{
register unsigned i;
register char *cp;
i = nelem * size;
cp = mallocw(i);
memset(cp,0,i);
return cp;
}
/* Return available memory on our heap plus available system memory */
unsigned long
availmem()
{
return Availmem * ABLKSIZE + coreleft();
}
/* Log heap stats */
static int
logstat(void)
{
if(Memdebug){
log(-1,"Memory status:");
log(-1,HeapSizeStr,Heapsize,Availmem*ABLKSIZE, \
100L*Availmem*ABLKSIZE/Heapsize,Morecores,coreleft());
log(-1,AllocStr,Allocs,Frees,Allocs-Frees,Memfail,Invalid,Overuse);
log(-1,GarbageStr,Yellows,Reds);
#ifdef notdef
log(-1,EfficientStr,Efficient,Memthresh);
#endif
log(-1,EfficientStr,Memthresh);
log(-1,InterruptStr,Intalloc,Intfree);
}
return 0;
}
/* Print heap stats */
int
dostat(argc,argv,envp)
int argc;
char *argv[];
void *envp;
{
#ifdef EMS
unsigned int emssize;
#endif
#ifdef XMS
long XMS_Ret;
#endif
tprintf(HeapSizeStr,Heapsize,Availmem*ABLKSIZE, \
100L*Availmem*ABLKSIZE/Heapsize,Morecores,coreleft());
tputc('\n');
tprintf(AllocStr,Allocs,Frees,Allocs-Frees,Memfail,Invalid,Overuse);
tputc('\n');
tprintf(Threshold,Memthresh);
tprintf(GarbageStr,Yellows,Reds);
tputc('\n');
tprintf(InterruptStr,Intalloc,Intfree);
iqstat();
#ifdef EMS
if(EMS_Available) {
if(ememmax(&emssize) == 0)
tprintf("EMS: %u bytes contiguous available.\n",emssize);
}
#endif
#ifdef XMS
if(XMS_Available) {
if((XMS_Ret = Total_XMS()) > 0L) {
tprintf("XMS: total %u KB, largest block: %u KB\n",
(unsigned) XMS_Ret, Query_XMS());
}
}
#endif
return 0;
}
/* Print heap free list */
static int
dofreelist(argc,argv,envp)
int argc;
char *argv[];
void *envp;
{
HEADER HUGE *p;
int i = 0;
for(p = Base.s.ptr;p !=(HEADER HUGE *) &Base;p = p->s.ptr){
tprintf("%4.4x %6lu",FP_SEG(p),p->s.size * ABLKSIZE);
if(++i == 5){
i = 0;
if(tputc('\n') == EOF)
return 0;
} else
tputs(" | ");
}
if(i != 0)
tputc('\n');
return 0;
}
static int
dosizes(argc,argv,p)
int argc;
char *argv[];
void *p;
{
int i;
for(i=0;i<16;i += 4){
tprintf("N>=%5u:%7ld| N>=%5u:%7ld| N>=%5u:%7ld| N>=%5u:%7ld\n",
1<<i,Sizes[i], 2<<i,Sizes[i+1],
4<<i,Sizes[i+2],8<<i,Sizes[i+3]);
}
return 0;
}
int
domem(argc,argv,p)
int argc;
char *argv[];
void *p;
{
if(argc == 1)
return dostat(0,NULL,NULL);
return subcmd(Memcmds,argc,argv,p);
}
static int
dothresh(argc,argv,p)
int argc;
char *argv[];
void *p;
{
return setlong(&Memthresh,"Free memory threshold (bytes)",argc,argv);
}
static int
donibufs(argc,argv,p)
int argc;
char *argv[];
void *p;
{
if(setint(&Nibufs,"Interrupt pool buffers",argc,argv) == 0){
iqclear();
return 0;
}
return 1;
}
static int
doibufsize(argc,argv,p)
int argc;
char *argv[];
void *p;
{
return setuns(&Ibufsize,"Interrupt buffer size",argc,argv);
}
void
gcollect(i,v1,v2)
int i; /* Args not used */
void *v1;
void *v2;
{
void (**fp)(int);
int red;
for(;;){
pause(1000L); /* Run every second */
#ifdef CONVERS
{
extern void check_buffer_overload(void);
check_buffer_overload();
}
#endif
/* If memory is low, collect some garbage. If memory is VERY
* low, invoke the garbage collection routines in "red" mode.
*/
if(availmem() < Memthresh){
if(availmem() < Memthresh/2){
red = 1;
Reds++;
} else {
red = 0;
Yellows++;
}
for(fp = Gcollect;*fp != NULL;fp++)
(**fp)(red);
}
}
}
#ifdef notdef
static int
doefficient(argc,argv,p)
int argc;
char *argv[];
void *p;
{
return setbool(&Efficient,"Efficient/slower mode",argc,argv);
}
#endif
static int
domemdebug(argc,argv,p)
int argc;
char *argv[];
void *p;
{
return setbool(&Memdebug,"\"Mem stat\" to log after failures",argc,argv);
}
#ifdef MULTITASK
static int
dominheap(argc,argv,p)
int argc;
char *argv[];
void *p;
{
return setuns(&Minheap,"Minimum free heap when shelled out",argc,argv);
}
#endif